package com.atguigu.gmall.order.service.impl;

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONArray;
import com.atguigu.gmall.common.constant.MqConst;
import com.atguigu.gmall.common.service.RabbitService;
import com.atguigu.gmall.common.util.HttpClientUtil;
import com.atguigu.gmall.model.enums.OrderStatus;
import com.atguigu.gmall.model.enums.ProcessStatus;
import com.atguigu.gmall.model.order.OrderDetail;
import com.atguigu.gmall.model.order.OrderInfo;
import com.atguigu.gmall.order.mapper.OrderDetailMapper;
import com.atguigu.gmall.order.mapper.OrderInfoMapper;
import com.atguigu.gmall.order.service.OrderService;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.data.crossstore.HashMapChangeSet;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Repository;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.CollectionUtils;

import java.lang.reflect.Array;
import java.util.*;
import java.util.stream.Collectors;

@Service
@Repository
public class OrderServiceImpl extends ServiceImpl<OrderInfoMapper, OrderInfo> implements OrderService {
    @Autowired
    private OrderInfoMapper orderInfoMapper;
    @Autowired
    private OrderDetailMapper orderDetailMapper;
    @Autowired
    private RedisTemplate redisTemplate;
    @Autowired
    private RabbitService rabbitService;


    @Value("${ware.url}")
    private String wareUrl;  // wareUrl = http://localhost:9001 软引用


    //提交订单
    @Override
    @Transactional(rollbackFor = Exception.class)
    public Long saveOrderInfo(OrderInfo orderInfo) {
        //  编写插入数据实现！
        //  需要赋值的字段： total_amount order_status user_id out_trade_no trade_body expire_time process_status
        orderInfo.sumTotalAmount();
        orderInfo.setOrderStatus(OrderStatus.UNPAID.name());
        //  第三方交易编号 保证唯一！
        String outTradeNo = "ATGUIGU" + System.currentTimeMillis() + "" + new Random().nextInt(1000);
        orderInfo.setOutTradeNo(outTradeNo);

        orderInfo.setTradeBody("啤酒饮料矿泉水,花生,瓜子,八宝粥。来来来把腿收一收..");
        //  expire_time 24 小时！
        Calendar calendar = Calendar.getInstance();
        calendar.add(Calendar.DATE, 1);
        orderInfo.setExpireTime(calendar.getTime());
        orderInfo.setOperateTime(new Date());
        orderInfo.setProcessStatus(ProcessStatus.UNPAID.name());
        orderInfoMapper.insert(orderInfo);

        //  插入订单明细！
        List<OrderDetail> orderDetailList = orderInfo.getOrderDetailList();
        orderDetailList.forEach(orderDetail -> {
            orderDetail.setOrderId(orderInfo.getId());
            orderDetailMapper.insert(orderDetail);
        });
        //  获取订单Id
        Long orderId = orderInfo.getId();
        //rabbitmq  message 通过用户意愿来修改（orderId）
        this.rabbitService.sendDelayMessage(MqConst.EXCHANGE_DIRECT_ORDER_CANCEL,
                MqConst.ROUTING_ORDER_CANCEL,
                orderId, MqConst.DELAY_TIME);
        return orderId;
    }

    @Override
    public String getTradeNo(String userId) {
//        生成一个流水号
        String tradeNo = UUID.randomUUID().toString();
//       使用redis中string类型
        String tradeNoKey = "tradeNo:" + userId;
        this.redisTemplate.opsForValue().set(tradeNoKey, tradeNo);
//        返回
        return tradeNo;
    }

    @Override
    public Boolean checkTradeCode(String tradeNo, String userId) {
        //  生成key  判断流水号
        String tradeNoKey = "tradeNo:" + userId;
        String tradeNoRedis = (String) this.redisTemplate.opsForValue().get(tradeNoKey);
        return tradeNo.equals(tradeNoRedis);
    }

    @Override
    public void deleteTradeNo(String userId) {
        //  生成key   删除流水号
        String tradeNoKey = "tradeNo:" + userId;
        this.redisTemplate.delete(tradeNoKey);
    }

    @Override
    public Boolean checkStock(Long skuId, Integer skuNum) {
        //   wareUrl = http://localhost:9001
        //  调用接口：http://localhost:9001/hasStock?skuId=10221&num=2
        String result = HttpClientUtil.doGet(wareUrl + "/hasStock?skuId=" + skuId + "&num=" + skuNum);
        //  返回值！ 看接口文档0：无库存   1：有库存
        return "1".equals(result);
    }

    @Override
    public IPage<OrderInfo> getPage(Page<OrderInfo> pageParam, String userId) {
        IPage<OrderInfo> page = orderInfoMapper.selectPageByUserId(pageParam, userId);
        page.getRecords().stream().forEach(item -> {
            item.setOrderStatusName(OrderStatus.getStatusNameByStatus(item.getOrderStatus()));
        });
        return page;
    }

    //取消订单更改状态
    @Override
    public void cancelOrder(Long orderId) {
//      创建订单对象
//        OrderInfo orderInfo = new OrderInfo();
//        orderInfo.setId(orderId);
//        orderInfo.setOrderStatus(OrderStatus.CLOSED.name());
//        orderInfo.setProcessStatus(ProcessStatus.CLOSED.name());
//        orderInfoMapper.updateById(orderInfo);
        //更新订单状态
        this.updateOrderStatus(orderId, ProcessStatus.CLOSED);
        //发送消息  关闭交易  service—payment 监听接受消息
        //  发送消息！ payment：允许 多种支付 ： 传递一个orderId，传递一个 paymentType!
        //  map.put("orderId",orderId); map.put("paymentType",？);  JSON.toJsonString(map);
        //  this.rabbitService.sendMessage(MqConst.EXCHANGE_DIRECT_PAYMENT_CLOSE,MqConst.ROUTING_PAYMENT_CLOSE,JSON.toJsonString(map));
        //  只允许选择一种支付方式！
        //  只有一个支付宝： 可以传递orderId
        rabbitService.sendMessage(
                MqConst.EXCHANGE_DIRECT_PAYMENT_CLOSE,
                MqConst.ROUTING_PAYMENT_CLOSE,
                orderId);
    }

    @Override
    public OrderInfo getOrderInfo(Long orderId) {
        OrderInfo orderInfo = orderInfoMapper.selectById(orderId);
//        判断
        if (orderInfo != null) {
            List<OrderDetail> orderDetailList = orderDetailMapper.selectList(new QueryWrapper<OrderDetail>().eq("order_id", orderId));
            orderInfo.setOrderDetailList(orderDetailList);
        }
        return orderInfo;
    }

    public void updateOrderStatus(Long orderId, ProcessStatus processStatus) {
        OrderInfo orderInfo = new OrderInfo();
        orderInfo.setId(orderId);
        //从进度状态中获取订单状态
        orderInfo.setOrderStatus(processStatus.getOrderStatus().name());
        orderInfo.setProcessStatus(processStatus.name());
        orderInfoMapper.updateById(orderInfo);
    }

    //发送消息给库存系统更改订单状态
    @Override
    public void sendOrderStatus(Long orderId) {
        //修改订单的状态 进程状态：已通知仓库
        this.updateOrderStatus(orderId, ProcessStatus.NOTIFIED_WARE);
        //根据订单Id来获取orderInfo{orderDetail}发送消息！
        OrderInfo orderInfo = this.getOrderInfo(orderId);
        //将orderInfo 部分数据变为map 集合
        Map<String, Object> map = this.initWare(orderInfo);
        //将map 变为Json 字符串
        this.rabbitService.sendMessage(
                MqConst.EXCHANGE_DIRECT_WARE_STOCK,
                MqConst.ROUTING_WARE_STOCK,
                JSON.toJSONString(map));
    }

    //将orderInfo 部分数据变为map 集合
    public Map<String, Object> initWare(OrderInfo orderInfo) {
        //声明一个集合
        HashMap<String, Object> map = new HashMap<>();
        map.put("orderId", orderInfo.getId());//添加订单系统的订单ID
        map.put("consignee", orderInfo.getConsignee());//收货人
        map.put("consigneeTel", orderInfo.getConsigneeTel());//收货电话
        map.put("orderComment", orderInfo.getOrderComment());//订单备注
        map.put("orderBody", orderInfo.getTradeBody());//订单概要
        map.put("deliveryAddress", orderInfo.getDeliveryAddress());//发货地址
        map.put("paymentWay", "2");//支付方式‘1’ 为货到付款，‘2’为在线支付。
        map.put("wareId", orderInfo.getWareId());// 仓库Id ，减库存拆单时需要使用！
        //  details:[{skuId:101,skuNum:1,skuName:’小米手64G’},{skuId:201,skuNum:1,skuName:’索尼耳机’}]
        //  获取到订单明细！
        List<OrderDetail> orderDetailList = orderInfo.getOrderDetailList();
        List<HashMap<String, Object>> maps = orderDetailList.stream().map(orderDetail -> {
            HashMap<String, Object> detailMap = new HashMap<>();
            detailMap.put("skuId", orderDetail.getSkuId());
            detailMap.put("skuNum", orderDetail.getSkuNum());
            detailMap.put("skuName", orderDetail.getSkuName());
            return detailMap;
        }).collect(Collectors.toList());
        map.put("details", maps);//添加购买商品明细
        //返回map集合
        return map;
    }

    @Override
    public List<OrderInfo> OrderSplit(String orderId, String wareSkuMap) {
        ArrayList<OrderInfo> orderInfoList = new ArrayList<>();
       /*
        1.  先获取到原始订单{知道哪个订单要被拆分}
        2.  wareSkuMap [{"wareId":"1","skuIds":["2","10"]},{"wareId":"2","skuIds":["3"]}]
            将其转换为能处理的对象！
        3.  创建子订单，并给子订单赋值 {计算价格}
        4.  保存子订单
        5.  将子订单保存到集合中！
        6.  修改原始订单状态
         */
        //获取原始订单
        OrderInfo orderInfo = this.getOrderInfo(Long.parseLong(orderId));
        //wareSkuMap 转换为List<Map>
        List<Map> mapList = JSON.parseArray(wareSkuMap, Map.class);
        //判断
        if (!CollectionUtils.isEmpty(mapList)) {
            //循环
            for (Map map : mapList) {
                //获取仓库Id
                String wareId = (String) map.get("wareId");
                //获取仓库对应的skuIds集合
                List<String> skuIdList = (List<String>) map.get("skuIds");
                //创建子订单
                OrderInfo subOrderInfo = new OrderInfo();
                //属性拷贝，将部分字段重新赋值
                BeanUtils.copyProperties(orderInfo, subOrderInfo);
                //将id设置为null  因为id是主键自增的
                subOrderInfo.setId(null);
                //  计算子订单的金额
                //  先获取到子订单明细！
                List<OrderDetail> orderDetailList = orderInfo.getOrderDetailList();
                //  声明一个子订单的订单明细集合！
                List<OrderDetail> subOrderDetailList = new ArrayList<>();
                //  循环判断：
                if (!CollectionUtils.isEmpty(orderDetailList)) {
                    for (OrderDetail orderDetail : orderDetailList) {
                        //遍历仓库的id 对应的skuId  22:1  23:2
                        for (String skuId : skuIdList) {
                            if (orderDetail.getSkuId().compareTo(Long.parseLong(skuId)) == 0) {
                                subOrderDetailList.add(orderDetail);
                            }
                        }
                    }
                }
                //  将子订单明细赋值给子订单！
                subOrderInfo.setOrderDetailList(subOrderDetailList);
                subOrderInfo.sumTotalAmount();
                //设置父订单的id
                subOrderInfo.setParentOrderId(Long.parseLong(orderId));
                //给仓库id赋值
                subOrderInfo.setWareId(wareId);
                //保存子订单
                this.saveOrderInfo(subOrderInfo);
                //将子订单保存到集合中
                orderInfoList.add(subOrderInfo);
            }
        }
        //修改原始订单状态
        this.updateOrderStatus(Long.parseLong(orderId),ProcessStatus.SPLIT);
        //返回数据
        return orderInfoList;
    }
    @Override
    public void cancelOrder(Long orderId, String flag) {
        //  更新订单状态！
        this.updateOrderStatus(orderId,ProcessStatus.CLOSED);
        //  关闭paymentInfo
        if ("2".equals(flag)){
            //  只有一个支付宝： 可以传递orderId
            this.rabbitService.sendMessage(MqConst.EXCHANGE_DIRECT_PAYMENT_CLOSE,MqConst.ROUTING_PAYMENT_CLOSE,orderId);
        }

    }
}
